package com.cxy.common.boot;

import com.cxy.common.util.ShutDownHookCache;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.time.Duration;

/*********************************************************
 * 文件名称：CxyCloudStopListener.java
 * 系统名称：CXY自定义系统
 * 模块名称：com.cxy.common.boot
 * 功能说明：启动监听器
 * 开发人员 @author：caoxy31978
 * 开发时间 @date：2023/6/28 13:31
 * 修改记录：程序版本  修改日期  修改人员  修改单号  修改说明
 *********************************************************/
@Slf4j
public class CxyCloudStopListener implements SpringApplicationRunListener, Ordered {

    private final SpringApplication application;

    private final String[] args;

    public CxyCloudStopListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
    }

    @Override
    public int getOrder() {
        return Integer.MAX_VALUE;
    }

    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
                                    ConfigurableEnvironment environment) {
        if (this.application != null && this.isAppNameExist(environment)) {
            String startMsg = "************************* CXY Server Starting *************************************";
            if (this.application.getMainApplicationClass() != null) {
                LoggerFactory.getLogger(this.application.getMainApplicationClass()).info(startMsg);
            } else {
                log.info(startMsg);
            }
        }
    }

    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        String appInfo = System.getProperty("AppInfo");
        if (appInfo != null && isAppNameExist(context)) {
            log.info("Show only application information and exit...");
            System.exit(1);
        }
    }

    @Override
    public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        if (isAppNameExist(context) && System.getProperty("AppPID") != null) {
            try {
                File pidFile = new File(".pid");
                if (pidFile.exists()) {
                    pidFile.delete();
                }
                pidFile.createNewFile();
                String pid = ManagementFactory.getRuntimeMXBean().getName();
                try (FileWriter writer = new FileWriter(pidFile);) {
                    writer.write(pid.substring(0, pid.indexOf("@")));
                }
            } catch (IOException e) {
                log.info("Writer pid error!");
            }
        }
        if (this.application != null && this.isAppNameExist(context)) {
            try {
                String startedMsg = "************************* CXY Server Started *************************************";
                String stoppedMsg = "************************* CXY Server Stopping *************************************";
                String shutDownId = "CxyCloudStopListener-Shutdown";
                Class<?> mainClass = this.application.getMainApplicationClass();
                Logger appLog = mainClass != null  ? LoggerFactory.getLogger(mainClass) : log;
                appLog.info(startedMsg);
                ShutDownHookCache.register(shutDownId, () -> {
                    appLog.info(stoppedMsg);
                });
            } catch (Exception e) {
            }
        }
    }

    private boolean isAppNameExist(ConfigurableEnvironment environment) {
        try {
            return StringUtils.isNotBlank(environment.getProperty(CxyCloudConstants.APP_NAME));
        } catch (Exception e) {
            return false;
        }
    }

    private boolean isAppNameExist(ConfigurableApplicationContext context) {
        return context != null && this.isAppNameExist(context.getEnvironment());
    }
}
